home *** CD-ROM | disk | FTP | other *** search
- |x|*|f6|*|f5|*|f4|*|f3|*|f2|*|f1|{bootstrap the function keys}|.
- jff/Change log:/|nsm$log|nqan|{locate & mark the Change log}|.
- cfucp1.1upd[begin,end]|n|f6ucp1.1upd|n|{get specified part}|.
- bsmbegin|n2fsbsmend|nqa,|{mark beginning and ending lines of this part}|.
- jmend|nf/>>>>/ d|g}|!|*c|f1|f4ramdisk:|f1|n|f5|{save next part to ramdisk:}|.
- |f3|f3|f3|{main extraction sequence}|.
- |xsmend|njfk/|d|e|f2|{extraction initialization, replaced by filename}|.
- {>>>> DIR.FIXES.TEXT}
- unit dir_fixes;
-
- { Change log:
- 25 Jul 90 (RTC): added some error handling code
- 18 Jul 90 (RTC): Created to fix limitations of dir.info under SFS
- }
-
- interface
-
- type
- dTimeRec = packed record
- min : 0..59;
- hour : 0..24
- end {dTimeRec};
-
- procedure get_lastblk(dunit : integer; var filename : string;
- var bytes : integer);
-
- procedure put_lastblk(dunit : integer; var filename : string;
- bytes : integer);
-
- procedure get_filetime(dunit : integer; var filename : string;
- var the_time : dTimeRec);
-
- procedure put_filetime(dunit : integer; var filename : string;
- the_time : dTimeRec);
-
- implementation
-
- uses
- {$U syslibr:kernel.code} kernel (directory,dirrange,dirblk,maxdir);
-
- function get_file(dunit : integer; var filename : string;
- var dir : directory) : dirrange;
-
- var i,j : dirrange;
-
- begin {get_file}
- unitread(dunit,dir,sizeof(directory),dirblk);
- j := 0 {invalid entry number, in case we don't find it};
- for i := 1 to maxdir do
- if filename = dir[i].dtid
- then j := i;
- get_file := j;
- if j = 0 then
- begin
- writeln;
- writeln(chr(7),'ERROR! File "',filename,
- '" missing from directory of unit #',dunit);
- end
- end {get_file};
-
- procedure put_file(dunit : integer; var dir : directory);
-
- begin {put_file}
- unitwrite(dunit,dir,sizeof(directory),dirblk);
- end {put_file};
-
- procedure get_lastblk{dunit : integer; var filename : string;
- var bytes : integer};
-
- var
- disk_dir : directory;
-
- begin {get_lastblk}
- bytes := disk_dir[get_file(dunit,filename,disk_dir)].dlastbyte
- end {get_lastblk};
-
- procedure put_lastblk{dunit : integer; var filename : string;
- bytes : integer};
-
- var
- item : dirrange;
- disk_dir : directory;
-
- begin {put_lastblk}
- item := get_file(dunit,filename,disk_dir);
- if item <> 0 then
- begin
- disk_dir[item].dlastbyte := bytes;
- put_file(dunit,disk_dir)
- end
- end {put_lastblk};
-
- procedure get_filetime{dunit : integer; var filename : string;
- var the_time : dTimeRec};
-
- var
- disk_dir : directory;
-
- begin {get_filetime}
- with the_time,disk_dir[get_file(dunit,filename,disk_dir)] do
- begin
- min := dminute; hour := (dhour + 24) mod 25 {pred(dhour)}
- end;
- end {get_filetime};
-
- procedure put_filetime{dunit : integer; var filename : string;
- the_time : dTimeRec};
-
- var
- item : dirrange;
- disk_dir : directory;
-
- begin {put_filetime}
- item := get_file(dunit,filename,disk_dir);
- if item <> 0 then
- with the_time,disk_dir[item] do
- begin
- dminute := min; dhour := succ(hour) mod 25;
- put_file(dunit,disk_dir)
- end
- end {put_filetime};
-
- end. { dir.fixes }
- {>>>> SENDER.TEXT}
- {$D AFS-} { indicates to compile to run without Adv. File Sys.}
-
- unit sender;
-
- interface
-
- {Change log:
- 25 Jul 90, V1.1: Fixed invalid time attribute bug RTC
- 18 Jul 90, V1.1: Fixed SFS limitations RTC
- 13 May 89, V1.1: Misc. cleanups to debug messages RTC
- 26 Apr 89, V1.1: minor cleanups RTC
- 16 Apr 89, V1.1: Fixed "garbage in buffer" bug RTC
- 13 Apr 89, V1.1: Added Version message RTC
- 14 Aug 88: Fixed timeout state bug RTC
- 07 Aug 88: Added conditional compilation for AFS/SFS difference RTC
- 31 Jul 88: Added Attributes Packets & cancel xfr request from receiver RTC
- 10 Jul 88: Converted to use screenops unit RTC
- 10 Jul 88: Fixed cleareol problem on filenames RTC
- 02 Jul 88: Fixed sinit 8th-bit prefix negotiation bug RTC
- 30 Jun 88: Added Binary and multiple file transfers RTC
-
- }
-
- procedure sendsw(var send_ok: boolean);
-
- procedure sen_version;
-
-
- implementation
-
- uses
- screenops, {RTC, 10 Jul 88}
- {$U kermglob.code} kermglob,
- {$U kermutil.code} kermutil,
- {$U kermpack.code} kermpack,
- {$B AFS+}
- {$U syslibr:attribute.code} attributes,
- {$E AFS+} {$B AFS-}
- {$U dir.fixes.code} dir_fixes,
- {$E AFS-}
- {$U syslibr:wild.code} wild,
- {$U syslibr:dir.info.code} dirinfo;
-
- const
- my_version = ' Sender Unit V1.1, 25 Jul 90';
-
-
- procedure sendsw{(var send_ok: boolean)};
-
- var
- do_attr, still_sending, discard, next_is_empty : boolean;
- files_to_send : D_listp;
- io_status: integer;
- heap: ^integer;
- {$B AFS-}
- this_file : D_listp;
- {$E AFS-}
-
- procedure openfile;
-
- (* resets file of appropriate type *)
-
- var
- dummy : boolean;
-
- begin
- if debug then
- debugwrite(concat('Opening ',xfilename));
- (*$I-*) (* turn off compiler i/o checking temporarily *)
- if f_is_binary
- then
- begin
- reset(b_file,xfilename);
- if io_result = 0 then
- {$B AFS+}
- dummy := get_attribute(b_file,FA_lastvalidbyte,last_blksize);
- {$E AFS+} {$B AFS-}
- get_lastblk(files_to_send^.dunit,xfilename,last_blksize);
- {$E AFS-}
- bufend := 0 {mark the buffer as empty!}
- end
- else reset(t_file,xfilename);
- (*$I+*) (* turn compiler i/o checking back on *)
- io_status := io_result;
- {$B AFS-}
- this_file := files_to_send;
- {$E AFS-}
- end; (* openfile *)
-
- function sinit: char;
-
- (* send init packet & receive other side's *)
-
- var num, len, i: integer; (* packet number and length *)
- ch: char;
-
- begin
- if debug then
- debugwrite('sinit');
-
- if numtry > maxtry then
- begin
- sinit := 'a';
- exit(sinit)
- end;
-
- num_try := num_try + 1;
- spar(packet);
-
- clear_buf(inport);
-
- refresh_screen(numtry,n);
-
- spack('S',n mod 64,10,packet);
-
- ch := rpack(len,num,recpkt);
-
- if (ch = 'N') then
- begin
- sinit := 's';
- exit(sinit)
- end (* if 'N' *)
- else if (ch = 'Y') then
- begin
- if ((n mod 64) <> num) then (* not the right ack *)
- begin
- sinit := currstate;
- exit(sinit)
- end;
- rpar(recpkt,len);
- if (xeol = chr(0)) then (* if they didn't spec eol *)
- xeol := chr(my_eol); (* use mine *)
- if (quote = chr(0)) then (* if they didn't spec quote *)
- quote := my_quote; (* use mine *)
- ctl_set := [chr(0)..chr(31),chr(del),quote];
- if en_qbin then ctl_set := ctl_set + [qbin];
- numtry := 0;
- n := n + 1; (* increase packet number *)
- sinit := 'f';
- exit(sinit)
- end (* else if 'Y' *)
- else if (ch = 'E') then
- begin
- error(recpkt,len);
- sinit := 'a'
- end (* if 'E' *)
- else if (ch = chr(0)) then
- sinit := currstate
- else if (ch <> 'N') then
- sinit := 'a'
- end; (* sinit *)
-
- function sattr: char;
-
- (* send attributes packet *)
-
- var num, len, pkt_len: integer;
- ch: char;
- got_attr : boolean;
- {$B AFS+}
- file_date : FA_chron;
- {$E AFS+} {$B AFS-}
- file_time : dTimeRec;
- {$E AFS-}
- packet : packettype;
-
- begin
- if debug then
- debugwrite('sattr');
-
- if numtry > maxtry then
- begin
- sattr := 'a';
- exit(sattr)
- end;
-
- num_try := num_try + 1;
-
- refresh_screen(numtry,n);
-
- {$B AFS+}
- if f_is_binary
- then got_attr := get_attribute(b_file,FA_revision_date,file_date)
- else got_attr := get_attribute(t_file,FA_revision_date,file_date);
- with file_date,date,time do
- {$E AFS+} {$B AFS-}
- get_filetime(this_file^.dunit,xfilename,file_time);
- with this_file^.D_date,file_time do
- {$E AFS-}
- begin
- packet[0] := '#'; { creation date attribute }
-
- packet[2] := chr(year div 10 + ord('0'));
- packet[3] := chr(year mod 10 + ord('0'));
- packet[4] := chr(month div 10 + ord('0'));
- packet[5] := chr(month mod 10 + ord('0'));
- packet[6] := chr(day div 10 + ord('0'));
- packet[7] := chr(day mod 10 + ord('0'));
- pkt_len := 8;
- if hour <> 24
- then {valid time}
- begin
- packet[8] := ' ';
- packet[9] := chr(hour div 10 + ord('0'));
- packet[10] := chr(hour mod 10 + ord('0'));
- packet[11] := ':';
- packet[12] := chr(min div 10 + ord('0'));
- packet[13] := chr(min mod 10 + ord('0'));
- packet[1] := tochar(chr(12)); { length }
- pkt_len := pkt_len + 6
- end
- else {invalid time}
- begin
- packet[1] := tochar(chr(6)); { length }
- end
- end;
-
- spack('A',n mod 64,pkt_len,packet);
-
- ch := rpack(len,num,recpkt);
-
- if (ch = 'N') then
- begin
- sattr := 'd';
- exit(sattr)
- end (* if 'N' *)
- else if (ch = 'Y') then
- begin
- if ((n mod 64) <> num) then (* not the right ack *)
- begin
- sattr := currstate;
- exit(sattr)
- end;
- numtry := 0;
- n := n + 1; (* increase packet number *)
- do_attr := false;
- discard := (len > 0) and (recpkt[0] = 'N');
- if discard
- then sattr := 'z'
- else sattr := 'd';
- exit(sattr)
- end (* else if 'Y' *)
- else if (ch = 'E') then
- begin
- error(recpkt,len);
- sattr := 'a'
- end (* if 'E' *)
- else if (ch = chr(0)) then
- sattr := currstate
- else if (ch <> 'N') then
- sattr := 'a'
- end; (* sattr *)
-
- function sdata: char;
-
- (* send file data *)
-
- var num, len: integer;
- ch: char;
- packarray: array[boolean] of packettype;
- sizearray: array[boolean] of integer;
- current: boolean;
- b: boolean;
-
- function other(b: boolean): boolean;
-
- (* complements a boolean which is used as array index *)
-
- begin
- if b then
- other := false
- else
- other := true
- end; (* other *)
-
- begin
- discard := false;
- current := true;
- packarray[current] := packet;
- sizearray[current] := size;
- next_is_empty := true;
- while (currstate = 'd') do
- begin
- if (numtry > maxtry) then (* if too many tries, give up *)
- currstate := 'a';
-
- b := other(current);
- numtry := numtry + 1;
-
- (* send a data packet *)
- spack('D',n mod 64,sizearray[current],packarray[current]);
-
- refresh_screen(numtry,n);
-
- if next_is_empty then (* set up next packet *)
- begin
- sizearray[b] := bufill(packarray[b]);
- next_is_empty := false
- end;
-
- ch := rpack(len,num,recpkt); (* receive a packet *)
- if ch = 'N' then (* NAK, so just stay in this state *)
- if ((n+1) mod 64 <> num) then (* unless NAK for next packet, which
- *)
- sdata := currstate
- else (* is just like ACK for this packet *
- )
- begin
- if num > 0 then
- num := (num - 1) (* in which case, decrement num *)
- else
- num := 63;
- ch := 'Y'; (* and indicate an ACK *)
- end; (* else *)
-
- if (ch = 'Y') then
- begin
- if ((n mod 64) <> num) then (* if wrong ACK *)
- (* stay in same state *)
- else
- begin
- numtry := 0;
- n := n + 1;
- current := b;
- next_is_empty := true;
- discard := sizearray[current] = at_badblk;
- if read_ch(keyport, ch) then {check for user canceling send}
- begin
- if ord(ch) in [can_cur,can_all]
- then discard := true;
- if ord(ch) = can_all
- then files_to_send := nil
- end;
- if len = 1 then {check for receiver canceling send}
- begin
- if recpkt[0] in ['X','Z']
- then discard := true;
- if recpkt[0] = 'Z'
- then files_to_send := nil
- end;
- if (sizearray[current] = at_eof) or discard then
- currstate := 'z' (* set state to eof *)
- else
- currstate := 'd' (* else stay in data state *)
- end {else}
- end (* if *)
- else if (ch = 'E') then
- begin
- error(recpkt,len);
- currstate := 'a'
- end (* if 'E' *)
- else if (ch = chr(0)) then (* receive failure, so stay in d *)
- else if (ch <> 'N') then
- currstate := 'a' (* on anything else goto abort st
- ate *)
- end; (* while *)
- size := sizearray[current];
- packet := packarray[current];
- sdata := currstate
- end; (* sdata *)
-
- function sfile: char;
-
- (* send file header *)
-
- var num, len, i: integer;
- ch: char;
- fn: packettype;
- oldfn: string255;
-
- procedure legalize(var fn: string255);
-
- (* make sure we send only 1 '.' in filename *)
-
- var count, i, j, l: integer;
-
- begin
- if not lit_names then
- begin
- count := 0;
- l := length(fn);
- for i := 1 to l do (* count '.'s in fn
- *)
- if fn[i] = '.' then
- count := count + 1;
- for i := 1 to count-1 do (* remove all but 1
- *)
- begin
- j := 1;
- while (j < l) and (fn[j] <> '.') do
- j := j + 1; (* by finding it *)
- fn := concat(copy(fn,1,j-1),copy(fn,j+1,l-j)); (* and copying arou
- nd it *)
- l := l - 1
- end (* for i *)
- end;
- i := pos(':',fn);
- if i <> 0 then
- fn := copy(fn,i+1,length(fn)-i) {remove Vol. name}
- end; (* legalize *)
-
- begin
- if debug then
- debugwrite('sfile');
-
- if (numtry > maxtry) then (* if too many tries, give up *)
- begin
- sfile := 'a';
- exit(sfile)
- end;
- numtry := numtry + 1;
-
- oldfn := xfilename;
- legalize(xfilename); (* make filename acceptable to remote *
- )
- len := length(xfilename);
-
- moveleft(xfilename[1],fn[0],len); (* move filename into a packettype *)
-
- SC_erase_to_EOL(filepos,fileline);
- write(oldfn,' ==> ',xfilename);
-
- refresh_screen(numtry,n);
-
- spack('F',n mod 64,len,fn); (* send file header packet *)
-
- if next_is_empty then
- begin
- size := bufill(packet); (* get first data from file *)
- next_is_empty := false
- end; (* while waiting for response *)
-
- ch := rpack(len,num,recpkt);
- if ch = 'N' then (* NAK, so just stay in this state *)
- if ((n+1) mod 64 <> num) then (* unless NAK for next packet, which *)
- begin
- sfile := 'f';
- exit(sfile) (* is just like ACK for this packet *)
- end
- else
- begin
- if (num > 0) then
- num := (num - 1) (* in which case, decrement num *)
- else
- num := 63;
- ch := 'Y'; (* and indicate an ACK *)
- end; (* else *)
-
- if (ch = 'Y') then
- begin
- if ((n mod 64) <> num) then (* if wrong ACK, stay in F state *)
- begin
- sfile := 'f';
- exit(sfile)
- end;
- numtry := 0;
- n := n + 1;
- do_attr := en_attr;
- sfile := 'd';
- end (* if *)
- else if (ch = 'E') then
- begin
- error(recpkt,len);
- sfile := 'a'
- end (* if 'E' *)
- else if (ch = chr(0)) then {stay in f state}
- sfile := 'f'
- else if (ch <> 'N') then (* don't recognize it *)
- sfile := 'a'
- end; (* sfile *)
-
- function seof: char;
-
- (* send end of file *)
-
- var num, len: integer;
- ch: char;
-
- begin
- if debug then
- debugwrite('seof');
-
- if (numtry > maxtry) then (* if too many tries, give up *)
- begin
- seof := 'a';
- exit(seof)
- end;
- numtry := numtry + 1;
-
- refresh_screen(numtry,n);
-
- packet[0] := 'D'; {set up in case of discard}
-
- spack('Z',(n mod 64),ord(discard),packet); (* send end of file packet *)
-
- if debug then
- debugwrite('seof1');
-
- ch := rpack(len,num,recpkt);
- if ch = 'N' then (* NAK, so just stay in this state *)
- if ((n+1) mod 64 <> num) then (* unless NAK for next packet, which *)
- begin
- seof := 'z';
- exit(seof) (* is just like ACK for this packet *)
- end
- else
- begin
- if num > 0 then
- num := (num - 1) (* in which case, decrement num *)
- else
- num := 63;
- ch := 'Y'; (* and indicate an ACK *)
- end; (* else *)
-
- if (ch = 'Y') then
- begin
- if debug then
- debugwrite('seof2');
- if ((n mod 64) <> num) then (* if wrong ACK, stay in Z state *)
- begin
- seof := 'z';
- exit(seof)
- end;
- numtry := 0;
- n := n + 1;
- if debug then
- debugwrite(concat('Closing ',xfilename));
- if f_is_binary
- then close(b_file)
- else close(t_file);
- while files_to_send <> nil do with files_to_send^ do
- begin
- xfilename := concat(D_volume,':',D_title);
- seof := 'f';
- next_is_empty := true;
-
- openfile;
- files_to_send := D_next_entry;
- if io_status <> 0
- then io_error(io_status)
- else exit(seof)
- end {while};
- seof := 'b'
- end (* if *)
- else if (ch = 'E') then
- begin
- error(recpkt,len);
- seof := 'a'
- end (* if 'E' *)
- else if (ch = chr(0)) then (* receive failed, so stay in z state *)
- seof := 'z'
- else if (ch <> 'N') then (* other error, just abort *)
- seof := 'a'
- end; (* seof *)
-
- function sbreak: char;
-
- var num, len: integer;
- ch: char;
-
- (* send break (end of transmission) *)
-
- begin
- if debug then
- debugwrite('sbreak');
-
- if (numtry > maxtry) then (* if too many tries, give up *)
- begin
- sbreak := 'a';
- exit(sbreak)
- end;
- numtry := numtry + 1;
-
- refresh_screen(numtry,n);
-
- spack('B',(n mod 64),0,packet); (* send Break Transfer packet *)
-
- ch := rpack(len,num,recpkt);
- if ch = 'N' then (* NAK, so just stay in this state *)
- if ((n+1) mod 64 <> num) then (* unless NAK for next packet, which *)
- begin
- sbreak := 'b';
- exit(sbreak) (* is just like ACK for this packet *)
- end
- else
- begin
- if num > 0 then
- num := (num - 1) (* in which case, decrement num *)
- else
- num := 63;
- ch := 'Y'; (* and indicate an ACK *)
- end; (* else *)
-
- if (ch = 'Y') then
- begin
- if ((n mod 64) <> num) then (* if wrong ACK, stay in B state *)
- begin
- sbreak := 'b';
- exit(sbreak)
- end;
- numtry := 0;
- n := n + 1;
- sbreak := 'c' (* else, switch state to complete *)
- end (* if *)
- else if (ch = 'E') then
- begin
- error(recpkt,len);
- sbreak := 'a'
- end (* if 'E' *)
- else if (ch = chr(0)) then (* receive failed, so stay in b state *)
- sbreak := 'b'
- else if (ch <> 'N') then (* other error, just abort *)
- sbreak := 'a'
- end; (* sbreak *)
-
- (* state table switcher for sending *)
-
- begin (* sendsw *)
- mark(heap);
- send_ok := false;
- still_sending :=
- D_dirlist(xfilename,[D_code..D_svol],files_to_send,false) = D_okay;
- if files_to_send <> nil then with files_to_send^ do
- begin
- xfilename := concat(D_volume,':',D_title);
- next_is_empty := true;
-
- openfile;
- files_to_send := D_next_entry;
- if io_status <> 0 then
- begin
- io_error(io_status);
- still_sending := false
- end
- end;
-
- if still_sending then write_screen('Sending');
- currstate := 's';
- n := 0; (* set packet # *)
- numtry := 0;
- flush_comm; {flush any garbage in buffer}
-
- while still_sending do
- if currstate in ['d', 'f', 'z', 's', 'b', 'c', 'a'] then
- case currstate of
- 'd': if do_attr
- then currstate := sattr
- else currstate := sdata;
- 'f': currstate := sfile;
- 'z': currstate := seof;
- 's': currstate := sinit;
- 'b': currstate := sbreak;
- 'c': begin
- send_ok := true;
- still_sending := false
- end; (* case c *)
- 'a': still_sending := false
- end (* case *)
- else (* state not in legal states *)
- begin
- debugwrite('Unknown State');
- still_sending := false
- end (* else *);
- release(heap)
- end; (* sendsw *)
-
- procedure sen_version;
-
- begin
- writeln(my_version)
- end {sen_version};
-
- end. { sender }
- {>>>> RECEIVER.TEXT}
- {$D AFS-} {indicates for compile to run without Adv. File Sys.}
-
- unit receiver;
-
- interface
-
- {Change log:
- 18 Jul 90, V1.1: Fixed SFS limitations RTC
- 18 May 89, V1.1: Added debugdate to reread file dates (fixed date bug[??]) RTC
- 13 May 89, V1.1: Misc. cleanup to debug messages RTC
- 30 Apr 89, V1.1: Fixed receiver won't stop on maxtry bug RTC
- 26 Apr 89, V1.1: minor cleanups RTC
- 16 Apr 89, V1.1: Fixed "garbage in buffer" bug RTC
- 16 Apr 89, V1.1: Fixed "short text filename" bug. RTC
- 15 Apr 89, V1.1: Added GET protocol & debug logging of date set result RTC
- 13 Apr 89, V1.1: Added version message RTC
- 17 Aug 88: Fixed garbage after partial last block of bin. file RTC
- 07 Aug 88: Added conditional compilation for AFS/SFS differences RTC
- 31 Jul 88: Added Attribute Packets & user discard requests to sender RTC
- 10 Jul 88: Converted to use screenops unit RTC
- 10 Jul 88: Fixed cleareol problem on filenames RTC
- 02 Jul 88: Added binary file transfer & discard protocol RTC
-
- }
-
- procedure recsw(var rec_ok: boolean; get_from_server : boolean);
-
- procedure rec_version;
-
-
- implementation
-
- uses
- screenops, {RTC, 10 Jul 88}
- {$U kermglob.code} kermglob,
- {$U kermutil.code} kermutil,
- {$U kermpack.code} kermpack,
- {$B AFS+}
- {$U syslibr:attribute.code} attributes;
- {$E AFS+} {$B AFS-}
- {$U dir.fixes.code} dir_fixes,
- {$U syslibr:wild.code} wild,
- {$U syslibr:dir.info.code} dirinfo;
- {$E AFS-}
-
- const
- my_version = ' Receiver Unit V1.1, 18 Jul 90';
-
- {$B AFS-}
- procedure debugdate;
-
- var
- heap : ^integer;
- list : D_listp;
- rslt : D_result;
-
- begin {debugdate}
- mark(heap);
- rslt := D_dirlist(xfilename,[Dvol..Ddir],list,false);
- if rslt <> D_okay then debugwrite('Can''t Access File Date');
- if debug then with list^,D_date do
- begin
- debugwrite('');
- write(debf,'File ',D_volume,':',D_title,' Current Date = ',
- month,'/',day,'/',year)
- end;
- release(heap)
- end {debugdate};
- {$E AFS-}
-
- procedure recsw{(var rec_ok: boolean; get_from_server : boolean)};
-
- var
- date_attr : record
- valid : boolean;
- value : {$B AFS+} FA_chron {$E AFS+}
- {$B AFS-}
- record
- date : D_daterec;
- time : D_timerec
- end;
- {$E AFS-}
- end;
-
- function bufattr(buffer : packettype; len : integer) : integer;
-
- var
- sp_pos,i,j,buffered : integer;
- tempattr : string;
-
- begin {bufattr}
- packet[0] := 'Y'; buffered := 1; {agree to accept file}
- i := 0; while i < len do
- begin
- if buffer[i] in ['#'] then {acceptable attribute}
- begin
- tempattr := '';
- for j := 1 to ord(unchar(buffer[succ(i)])) do
- begin
- tempattr := concat(tempattr,' ');
- tempattr[length(tempattr)] := buffer[succ(i) + j]
- end;
- case buffer[i] of
- '#' : with date_attr,value,date,time do
- begin
- sp_pos := pos(' ',tempattr);
- if sp_pos = 0 then sp_pos := succ(length(tempattr));
- year := (ord(tempattr[sp_pos-6]) - ord('0')) * 10
- + (ord(tempattr[sp_pos-5]) - ord('0'));
- month := (ord(tempattr[sp_pos-4]) - ord('0')) * 10
- + (ord(tempattr[sp_pos-3]) - ord('0'));
- day := (ord(tempattr[sp_pos-2]) - ord('0')) * 10
- + (ord(tempattr[sp_pos-1]) - ord('0'));
- if length(tempattr) > sp_pos then
- begin
- hour := (ord(tempattr[sp_pos+1]) - ord('0')) * 10
- + (ord(tempattr[sp_pos+2]) - ord('0'));
- min := (ord(tempattr[sp_pos+4]) - ord('0')) * 10
- + (ord(tempattr[sp_pos+5]) - ord('0'))
- end
- else {no time provided}
- begin
- hour := 24 {non-valid time}; min := 0
- end;
- valid := true
- end
- end {case}
- end
- else {reject attribute}
- begin
- packet[buffered] := buffer[i];
- buffered := succ(buffered)
- end;
- i := succ(succ(i) + ord(unchar(buffer[succ(i)])))
- end;
- bufattr := buffered
- end {bufattr};
-
- function rdata: char;
-
- (* receive file data *)
-
- var dummy, num, len: integer;
- ch: char;
- {$B AFS+}
- did_attr : boolean;
- {$E AFS+} {$B AFS-}
- heap : ^integer;
- this_file : D_listp;
- {$E AFS-}
- i: integer;
-
- begin
-
- repeat
- debugwrite('rdata');
-
- if numtry > maxtry then
- begin
- currstate := 'a';
- exit(rdata)
- end;
- num_try := num_try + 1;
-
- ch := rpack(len,num,recpkt); (* receive a packet *)
-
- refresh_screen(numtry,n);
-
- if (ch = 'D') then (* got data packet *)
- begin
- if (num <> (n mod 64)) then (* wrong packet *)
- begin
- if (oldtry > maxtry) then
- begin
- rdata := 'a'; (* too many tries, abort *)
- exit(rdata)
- end; (* if *)
-
- if (num = (pred(n) mod 64)) then (* previous packet again *)
- begin (* so re-ACK it *)
- spack('Y',num,0,packet);
- numtry := 0; (* reset try counter *)
- (* stay in same state *)
- end (* if *)
- else (* wrong number *)
- currstate := 'a' (* so abort *)
- end (* if *)
- else (* right packet *)
- begin
- bufemp(recpkt,len); (* write data to file *)
- if read_ch(keyport, ch) then {check if user wants to can}
- packet[0] := ctl(ch);
- spack('Y',(n mod 64),ord(ord(ch) in [can_cur,can_all]),
- packet); (* ACK packet *)
- oldtry := numtry; (* reset try counters *)
- numtry := 0;
- n := n + 1 (* bump packet number *)
- (* stay in data receive state *)
- end (* else *)
- end (* if 'D' *)
- else if ch = 'A' then { Attributes }
- begin
- if (num <> (n mod 64)) then (* wrong packet *)
- begin
- if (oldtry > maxtry) then
- begin
- rdata := 'a'; (* too many tries, abort *)
- exit(rdata)
- end; (* if *)
-
- if (num = (pred(n) mod 64)) then (* previous packet again *)
- begin (* so re-ACK it *)
- spack('Y',num,0,packet);
- numtry := 0; (* reset try counter *)
- (* stay in same state *)
- end (* if *)
- else (* wrong number *)
- currstate := 'a' (* so abort *)
- end (* if *)
- else (* right packet *)
- begin
- spack('Y',(n mod 64),bufattr(recpkt,len),packet); (* ACK packet
- *)
- oldtry := numtry; (* reset try counters *)
- numtry := 0;
- n := n + 1 (* bump packet number *)
- (* stay in data receive state *)
- end (* else *)
- end {if 'A'}
- else if (ch = 'F') then (* file header *)
- begin
- if (oldtry > maxtry) then
- begin
- rdata := 'a'; (* too many tries, abort *)
- exit(rdata)
- end; (* if *)
-
- if (num = (pred(n) mod 64)) then (* previous packet again *)
- begin (* so re-ACK it *)
- spack('Y',num,0,packet);
- numtry := 0; (* reset try counter *)
- (* stay in same state *)
- end (* if *)
- else
- currstate := 'a' (* not previous packet, abort *)
- end (* if 'F' *)
- else if (ch = 'Z') then (* end of file *)
- begin
- if (num <> (n mod 64)) then(* wrong packet, abort *)
- begin
- rdata := 'a';
- exit(rdata)
- end; (* if *)
- spack('Y',n mod 64,0,packet); (* ok, ACK it *)
- if (len = 1) and (recpkt[0] = 'D')
- then
- begin
- debugwrite(concat('Discarding ',xfilename));
- if f_is_binary {discard the file}
- then close(b_file)
- else close(t_file)
- end
- else
- begin
- debugwrite(concat('Closing ',xfilename));
- if f_is_binary (* close up the file *)
- then
- begin
- if bufpos > 1 {data in last block}
- then
- begin
- for dummy := bufpos to blksize do
- filebuf[dummy] := chr(0);
- dummy := blockwrite(b_file,filebuf,1);
- {$B AFS+}
- dummy := pred(bufpos);
- did_attr :=
- put_attribute(b_file,FA_lastvalidbyte,dummy)
- {$E AFS+}
- end;
- {$B AFS+}
- with date_attr do if valid then {set date}
- did_attr :=
- put_attribute(b_file,FA_revisiondate,value);
- {$E AFS+}
- close(b_file,lock)
- end
- else
- begin
- {$B AFS+}
- with date_attr do if valid then {set date}
- did_attr :=
- put_attribute(t_file,FA_creationdate,value);
- {$E AFS+}
- close(t_file,lock)
- end;
- {$B AFS-}
- mark(heap);
- if D_dirlist(xfilename,[D_code,D_text,D_data,D_svol],
- this_file,false) <> D_okay
- then {we have an error... should never occur}
- begin
- this_file := nil;
- debugwrite('Can''t locate Unit containing File')
- end
- else if f_is_binary and (bufpos > 1) then
- put_lastbyte(this_file^.dunit,xfilename,pred(bufpos));
- debugdate;
- with date_attr do if valid then {set date,time}
- begin
- case D_changedate(xfilename,value.date,
- [D_code,D_text,D_data,D_svol]) of
- D_okay : debugwrite('Date set OK');
- D_notfound : debugwrite('No such File, Date not set');
- D_nameerror : debugwrite('Name error, Date not set');
- D_offline : debugwrite('Volume offline, Date not set'
- );
- D_other : debugwrite('Unknown error, Date not set')
- ;
- end {case};
- if this_file <> nil
- then put_filetime(this_file^.dunit,xfilename,value.time
- )
- end;
- debugdate;
- release(heap);
- {$E AFS-}
- end;
- bufpos := 1; {clean up binary file buffer}
- n := n + 1; (* bump packet counter *)
- currstate := 'f'; (* go to complete state *)
- end (* else if 'Z' *)
- else if (ch = 'E') then (* error packet *)
- begin
- error(recpkt,len); (* display error *)
- currstate := 'a' (* and abort *)
- end (* if 'E' *)
- else if (ch <> chr(0)) then (* some other packet type, *)
- currstate := 'a' (* abort *)
- until (currstate <> 'd');
- rdata := currstate
- end; (* rdata *)
-
- function rfile: char;
-
- (* receive file header *)
-
- var num, len: integer;
- ch: char;
- oldfn: string255;
- i: integer;
-
- procedure makename(recpkt: packettype; var fn: string255; l: integer);
-
- function exist(fn: string255): boolean;
-
- (* returns true if file named fn exists *)
-
- var f: file;
-
- begin
- (*$I-*) (* turn off i/o checking *)
- reset(f,fn);
- exist := (ioresult = 0);
- (*$I+*)
- end; (* exist *)
-
- procedure checkname(var fn: string255);
-
- (* if file fn exists, makes a new name which doesn't *)
- (* does this by changing letters in file name until it *)
- (* finds some combination which doesn't exitst *)
-
- var ch: char;
- i: integer;
-
- begin
- i := 1;
- while (i <= length(fn)) and exist(fn) do
- begin
- ch := succ(fn[i]); {RTC, 13 May 89}
- if not (ch in ['A'..'Z']) then ch := 'A';
- while (ch in ['A'..'Z']) and exist(fn) do
- begin
- fn[i] := ch;
- ch := succ(ch);
- end; (* while *)
- i := i + 1
- end; (* while *)
- end; (* checkname *)
-
- begin (* makename *)
- fn := copy(' ',1,15); (* stretch length *)
- moveleft(recpkt[0],fn[1],l); (* get filename from packet *)
- oldfn := copy(fn, 1,l); (* save fn sent to show user *)
- fn := copy(fn,1,min(15,l)); (* set length of filename *)
- (* and make sure <= 15 *)
- uppercase(fn);
- if not f_is_binary then
- if (pos('.TEXT',fn) <> length(fn)-4) or (length(fn) < 5) then
- begin
- if length(fn) > 10 then
- fn := copy(fn,1,10); (* can only be 15 long in all *)
- fn := concat(fn,'.TEXT'); (* and we'll add .TEXT *)
- end; (* if *)
- if fwarn then (* if file warning is on *)
- checkname(fn); (* must check that name unique *)
- end; (* makename *)
-
- begin (* rfile *)
- debugwrite('rfile');
-
- if (numtry > maxtry) then (* if too many tries, give up *)
- begin
- rfile := 'a';
- exit(rfile)
- end;
- numtry := numtry + 1;
-
- ch := rpack(len,num,recpkt); (* receive a packet *)
-
- refresh_screen(numtry,n);
-
- if ch = 'S' then (* send init, maybe our ACK lost *)
- begin
- if (oldtry > maxtry) then (* too many tries, abort *)
- begin
- rfile := 'a';
- exit(rfile)
- end; (* if *)
-
- if num = (pred(n) mod 64) then (* previous packet mod 64? *)
- begin (* yes, ACK it again *)
- spar(packet); (* with our send init params *)
- spack('Y',num,10,packet);
- numtry := 0; (* reset try counter *)
- rfile := currstate; (* stay in same state *)
- end (* if *)
- else (* not previous packet, abort *)
- rfile := 'a'
- end (* if 'S' *)
- else if (ch = 'Z') then (* end of file *)
- begin
- if (oldtry > maxtry) then (* too many tries, abort *)
- begin
- rfile := 'a';
- exit(rfile)
- end; (* if *)
-
- if num = (pred(n) mod 64) then (* previous packet mod 64? *)
- begin (* yes, ACK it again *)
- spack('Y',num,0,packet);
- numtry := 0;
- rfile := currstate (* stay in same state *)
- end (* if *)
- else
- rfile := 'a' (* no, abort *)
- end (* else if *)
- else if (ch = 'F') then (* file header *)
- begin (* which is what we really want *)
- if (num <> (n mod 64)) then (* if wrong packet, abort *)
- begin
- rfile := 'a';
- exit(rfile)
- end;
-
- makename(recpkt,xfilename,len); (* get filename, make unique if filew *
- )
- SC_erase_to_EOL(filepos,fileline);
- write(oldfn,' ==> ',xfilename);
-
- if not getfil(xfilename) then (* try to open new file *)
- begin
- ioerror(ioresult); (* if unsuccessful, tell them *)
- rfile := 'a'; (* and abort *)
- exit(rfile)
- end; (* if *)
-
- spack('Y',n mod 64,0,packet); (* ACK file header *)
-
- {initializations for file attribute data}
- date_attr.valid := false;
- {end of initializations for file attribute data}
-
- oldtry := numtry; (* reset try counters *)
- numtry := 0;
- n := n + 1; (* bump packet number *)
- rfile := 'd'; (* switch to data state *)
- end (* else if *)
- else if ch = 'B' then (* break transmission *)
- begin
- if (num <> (n mod 64)) then (* wrong packet, abort *)
- begin
- rfile := 'a';
- exit(rfile)
- end;
- spack('Y',n mod 64,0,packet); (* say ok *)
- rfile := 'c' (* go to complete state *)
- end (* else if *)
- else if (ch = 'E') then
- begin
- error(recpkt,len);
- rfile := 'a'
- end
- else if (ch = chr(0)) then (* returned false *)
- rfile := currstate (* so stay in same state *)
- else (* some weird state, so abort *)
- rfile := 'a'
- end; (* rfile *)
-
- function rinit: char;
-
- (* receive initialization *)
-
- var num, len: integer; (* packet number and length *)
- ch: char;
- fn : packettype;
-
- begin
- debugwrite('rinit');
-
- if (numtry > maxtry) then (* if too many tries, give up *)
- begin
- rinit := 'a';
- exit(rinit)
- end;
- numtry := numtry + 1;
-
- if get_from_server then {ask server for files}
- begin
- len := length(xfilename);
- moveleft(xfilename[1],fn[0],len);
- spack('R', n mod 64, len, fn)
- end;
-
- ch := rpack(len,num,recpkt); (* receive a packet *)
- refresh_screen(num_try,n);
-
- if (ch = 'S') then (* send init packet *)
- begin
- rpar(recpkt,len); (* get other side's init data *)
- spar(packet); (* fill packet with my init data *)
- ctl_set := [chr(0)..chr(31),chr(del),quote];
- if en_qbin then ctl_set := ctl_set + [qbin];
- spack('Y',n mod 64,10,packet); (* ACK with my params *)
- get_from_server := false;
- oldtry := numtry; (* save old try count *)
- numtry := 0; (* start a new counter *)
- n := n + 1; (* bump packet number *)
- rinit := 'f'; (* enter file receive state *)
- end (* if 'S' *)
- else if ch = 'Y' then
- begin
- rinit := 'r';
- if n mod 64 = num then {we have the right ACK}
- begin
- get_from_server := false;
- numtry := 0;
- n := n + 1
- end
- end {if 'Y'}
- else if (ch = 'E') then
- begin
- rinit := 'a';
- error(recpkt,len)
- end (* if 'E' *)
- else if (ch = chr(0)) or (ch = 'N') then
- rinit := 'r' (* stay in same state *)
- else
- rinit := 'a' (* abort *)
- end; (* rinit *)
-
- (* state table switcher for receiving packets *)
-
- begin (* recswok *)
- rec_ok := false;
- writescreen('Receiving');
- currstate := 'r'; (* initial state is receive *)
- n := 0; (* set packet # *)
- numtry := 0; (* no tries yet *)
- flush_comm; {flush any garbage in buffer}
-
- while true do
- if currstate in ['d', 'f', 'r', 'c', 'a'] then
- case currstate of
- 'd': currstate := rdata;
- 'f': currstate := rfile;
- 'r': currstate := rinit;
- 'c': begin
- rec_ok := true;
- exit(recsw)
- end; (* case c *)
- 'a': exit(recsw)
- end (* case *)
- else (* state not in legal states *)
- begin
- debugwrite('Unknown State');
- exit(recsw)
- end (* else *)
- end; (* recsw *)
-
- procedure rec_version;
-
- begin
- writeln(my_version)
- end {rec_version};
-
- end. { receiver }
- {>>>>}
-